package org.exteen;

import java.io.PrintStream;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;
import java.util.Map;

import org.exteen.exec.ExteenContext;
import org.exteen.exec.RootExteenContext;
import org.exteen.exec.Tag;
import org.exteen.exec.TopContext;
import org.exteen.output.ExteenStream;
import org.exteen.parser.Node;
import org.exteen.tag.core.RootTag;

/**
 * Serves a method is to compile script with given context. Output goes to stream or writer. 
 *
 */
public class Script {

    private final Node rootNode;
    private final URL sourceURL;
    private final ScriptParser scriptParser;

    public Script(Node node, URL sourceURL, ScriptParser scriptParser) {
        this.rootNode = node;
        this.sourceURL = sourceURL;
        this.scriptParser = scriptParser;
    }

    public void compileTo(Writer writer, Map<String, Object> map) {
        TopContext topContext = new TopContext(map, scriptParser.getBootLibraries());
        doScript(topContext, scriptParser.getDefaultStream(writer));
    }

    public void compileTo(ExteenStream stream, Map<String, Object> map) {
        TopContext topContext = new TopContext(map, scriptParser.getBootLibraries());
        doScript(topContext, stream);
    }

    public void compileTo(PrintStream ps, Map<String, Object> map) {
        StringWriter writer = new StringWriter();
        compileTo(writer, map);
        ps.print(writer);
    }

    public void doScript(ExteenContext ctx, ExteenStream stream) {
        Tag tag = ctx.getTagForNode(rootNode);
        if (!(tag instanceof RootTag)) {
            throw new ExteenException("The root tag of the script must be a 'script' tag from exteen:core library");
        }
        ExteenContext rootContext = new RootExteenContext(ctx, rootNode, this);
        tag.doBody(rootContext, stream);
        rootContext.mergeToParent();
    }

    public URL getSourceURL() {
        return sourceURL;
    }

    public ScriptParser getParser() {
        return scriptParser;
    }
}
